home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / ip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  12.0 KB  |  505 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  */
  5. #include "global.h"
  6. #include "config.h"
  7. #include "mbuf.h"
  8. #include "timer.h"
  9. #include "internet.h"
  10. #include "iface.h"
  11. #include "ip.h"
  12. #include "icmp.h"
  13. #include "tcp.h"
  14. #include "udp.h"
  15. #include "rspf.h"
  16.  
  17. static struct mbuf *fraghandle __ARGS((struct ip *ip,struct mbuf *bp));
  18. static void ip_timeout __ARGS((void *arg));
  19. static void free_reasm __ARGS((struct reasm *rp));
  20. static void freefrag __ARGS((struct frag *fp));
  21. static struct reasm *lookup_reasm __ARGS((struct ip *ip));
  22. static struct reasm *creat_reasm __ARGS((struct ip *ip));
  23. static struct frag *newfrag __ARGS((int16 offset,int16 last,struct mbuf *bp));
  24.  
  25. struct mib_entry Ip_mib[20] = {
  26.     "",            0,
  27.     "ipForwarding",        1,
  28.     "ipDefaultTTL",        MAXTTL,
  29.     "ipInReceives",        0,
  30.     "ipInHdrErrors",    0,
  31.     "ipInAddrErrors",    0,
  32.     "ipForwDatagrams",    0,
  33.     "ipInUnknownProtos",    0,
  34.     "ipInDiscards",        0,
  35.     "ipInDelivers",        0,
  36.     "ipOutRequests",    0,
  37.     "ipOutDiscards",    0,
  38.     "ipOutNoRoutes",    0,
  39.     "ipReasmTimeout",    TLB,
  40.     "ipReasmReqds",        0,
  41.     "ipReasmOKs",        0,
  42.     "ipReasmFails",        0,
  43.     "ipFragOKs",        0,
  44.     "ipFragFails",        0,
  45.     "ipFragCreates",    0,
  46. };
  47.  
  48. struct reasm *Reasmq;
  49. static struct raw_ip *Raw_ip;
  50.  
  51. #define    INSERT    0
  52. #define    APPEND    1
  53. #define    PREPEND    2
  54.  
  55. /* Send an IP datagram. Modeled after the example interface on p 32 of
  56.  * RFC 791
  57.  */
  58. int
  59. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  60. int32 source;            /* source address */
  61. int32 dest;            /* Destination address */
  62. char protocol;            /* Protocol */
  63. char tos;            /* Type of service */
  64. char ttl;            /* Time-to-live */
  65. struct mbuf *bp;        /* Data portion of datagram */
  66. int16 length;            /* Optional length of data portion */
  67. int16 id;            /* Optional identification */
  68. char df;            /* Don't-fragment flag */
  69. {
  70.     struct mbuf *tbp;
  71.     struct ip ip;        /* Pointer to IP header */
  72.     static int16 id_cntr;    /* Datagram serial number */
  73.     struct phdr *phdr;
  74.  
  75.     ipOutRequests++;
  76.  
  77.     if(source == INADDR_ANY)
  78.         source = locaddr(dest);
  79.     if(length == 0 && bp != NULLBUF)
  80.         length = len_p(bp);
  81.     if(id == 0)
  82.         id = id_cntr++;        
  83.     if(ttl == 0)
  84.         ttl = ipDefaultTTL;
  85.  
  86.     /* Fill in IP header */
  87.     ip.tos = tos;
  88.     ip.length = IPLEN + length;
  89.     ip.id = id;
  90.     ip.offset = 0;
  91.     ip.flags.mf = 0;
  92.     ip.flags.df = df;
  93.     ip.ttl = ttl;
  94.     ip.protocol = protocol;
  95.     ip.source = source;
  96.     ip.dest = dest;
  97.     ip.optlen = 0;
  98.     if((tbp = htonip(&ip,bp,0)) == NULLBUF){
  99.         free_p(bp);
  100.         return -1;
  101.     }
  102.     if((bp = pushdown(tbp,sizeof(struct phdr))) == NULLBUF){
  103.         free_p(tbp);
  104.         return -1;
  105.     }
  106.     phdr = (struct phdr *)bp->data;
  107.     if(ismyaddr(ip.dest)){
  108.         /* Pretend it has been sent by the loopback interface before
  109.          * it appears in the receive queue
  110.          */
  111.         phdr->iface = &Loopback;
  112.         Loopback.ipsndcnt++;
  113.         Loopback.rawsndcnt++;
  114.         Loopback.lastsent = Clock;
  115.     } else
  116.         phdr->iface = NULLIF;
  117.     phdr->type = TYPE_NONE;
  118.     enqueue(&Hopper,bp);
  119.     return 0;
  120. }
  121.  
  122. /* Reassemble incoming IP fragments and dispatch completed datagrams
  123.  * to the proper transport module
  124.  */
  125. void
  126. ip_recv(iface,ip,bp,rxbroadcast)
  127. struct iface *iface;    /* Incoming interface */
  128. struct ip *ip;        /* Extracted IP header */
  129. struct mbuf *bp;    /* Data portion */
  130. int rxbroadcast;    /* True if received on subnet broadcast address */
  131. {
  132.     /* Function to call with completed datagram */
  133.     register struct raw_ip *rp;
  134.     struct mbuf *bp1,*tbp;
  135.     int rxcnt = 0;
  136.  
  137.     /* If we have a complete packet, call the next layer
  138.      * to handle the result. Note that fraghandle passes back
  139.      * a length field that does NOT include the IP header
  140.      */
  141.     if((bp = fraghandle(ip,bp)) == NULLBUF)
  142.         return;        /* Not done yet */
  143.  
  144.     ipInDelivers++;
  145.  
  146.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next){
  147.         if(rp->protocol != ip->protocol)
  148.             continue;
  149.         rxcnt++;
  150.         /* Duplicate the data portion, and put the header back on */
  151.         dup_p(&bp1,bp,0,len_p(bp));
  152.         if(bp1 != NULLBUF && (tbp = htonip(ip,bp1,1)) != NULLBUF){
  153.             enqueue(&rp->rcvq,tbp);
  154.             if(rp->r_upcall != NULLVFP)
  155.                 (*rp->r_upcall)(rp);
  156.         } else {
  157.             free_p(bp1);
  158.         }
  159.     }
  160.     /* Check for protocols we can't handle */
  161.     switch(uchar(ip->protocol)){
  162.     case TCP_PTCL:
  163.         tcp_input(bp,ip,rxbroadcast);
  164.         break;
  165.     case UDP_PTCL:
  166.         udp_input(iface,bp,ip,rxbroadcast);
  167.         break;
  168.     case ICMP_PTCL:
  169.         icmp_input(bp,ip,rxbroadcast);
  170.         break;
  171. #ifdef    RSPF
  172.     case RSPF_PTCL:
  173.         rspf_input(iface,ip,bp,rxbroadcast);
  174.         break;
  175. #endif    /* RSPF */
  176.     default:
  177.         if(rxcnt == 0){
  178.             /* Send an ICMP Protocol Unknown response... */
  179.             ipInUnknownProtos++;
  180.             /* ...unless it's a broadcast */
  181.             if(!rxbroadcast){
  182.                 icmp_output(ip,bp,ICMP_DEST_UNREACH,
  183.                  ICMP_PROT_UNREACH,(union icmp_args *)NULL);
  184.             }
  185.         }
  186.         free_p(bp);
  187.         break;
  188.     }
  189. }
  190. /* Process IP datagram fragments
  191.  * If datagram is complete, return it with ip->length containing the data
  192.  * length (MINUS header); otherwise return NULLBUF
  193.  */
  194. static
  195. struct mbuf *
  196. fraghandle(ip,bp)
  197. struct ip *ip;        /* IP header, host byte order */
  198. struct mbuf *bp;    /* The fragment itself */
  199. {
  200.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  201.     struct frag *lastfrag,*nextfrag,*tfp;
  202.     struct mbuf *tbp;
  203.     int16 i;
  204.     int16 last;        /* Index of first byte beyond fragment */
  205.  
  206.     last = ip->offset + ip->length - (IPLEN + ip->optlen);
  207.  
  208.     rp = lookup_reasm(ip);
  209.     if(ip->offset == 0 && !ip->flags.mf){
  210.         /* Complete datagram received. Discard any earlier fragments */
  211.         if(rp != NULLREASM){
  212.             free_reasm(rp);
  213.             ipReasmOKs++;
  214.         }
  215.         return bp;
  216.     }
  217.     ipReasmReqds++;
  218.     if(rp == NULLREASM){
  219.         /* First fragment; create new reassembly descriptor */
  220.         if((rp = creat_reasm(ip)) == NULLREASM){
  221.             /* No space for descriptor, drop fragment */
  222.             ipReasmFails++;
  223.             free_p(bp);
  224.             return NULLBUF;
  225.         }
  226.     }
  227.     /* Keep restarting timer as long as we keep getting fragments */
  228.     stop_timer(&rp->timer);
  229.     start_timer(&rp->timer);
  230.  
  231.     /* If this is the last fragment, we now know how long the
  232.      * entire datagram is; record it
  233.      */
  234.     if(!ip->flags.mf)
  235.         rp->length = last;
  236.  
  237.     /* Set nextfrag to the first fragment which begins after us,
  238.      * and lastfrag to the last fragment which begins before us
  239.      */
  240.     lastfrag = NULLFRAG;
  241.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  242.         if(nextfrag->offset > ip->offset)
  243.             break;
  244.         lastfrag = nextfrag;
  245.     }
  246.     /* Check for overlap with preceeding fragment */
  247.     if(lastfrag != NULLFRAG  && ip->offset < lastfrag->last){
  248.         /* Strip overlap from new fragment */
  249.         i = lastfrag->last - ip->offset;
  250.         pullup(&bp,NULLCHAR,i);
  251.         if(bp == NULLBUF)
  252.             return NULLBUF;    /* Nothing left */
  253.         ip->offset += i;
  254.     }
  255.     /* Look for overlap with succeeding segments */
  256.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  257.         tfp = nextfrag->next;    /* save in case we delete fp */
  258.  
  259.         if(nextfrag->offset >= last)
  260.             break;    /* Past our end */
  261.         /* Trim the front of this entry; if nothing is
  262.          * left, remove it.
  263.          */
  264.         i = last - nextfrag->offset;
  265.         pullup(&nextfrag->buf,NULLCHAR,i);
  266.         if(nextfrag->buf == NULLBUF){
  267.             /* superseded; delete from list */
  268.             if(nextfrag->prev != NULLFRAG)
  269.                 nextfrag->prev->next = nextfrag->next;
  270.             else
  271.                 rp->fraglist = nextfrag->next;
  272.             if(tfp->next != NULLFRAG)
  273.                 nextfrag->next->prev = nextfrag->prev;
  274.             freefrag(nextfrag);
  275.         } else
  276.             nextfrag->offset = last;
  277.     }
  278.     /* Lastfrag now points, as before, to the fragment before us;
  279.      * nextfrag points at the next fragment. Check to see if we can
  280.      * join to either or both fragments.
  281.      */
  282.     i = INSERT;
  283.     if(lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  284.         i |= APPEND;
  285.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  286.         i |= PREPEND;
  287.     switch(i){
  288.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  289.         tfp = newfrag(ip->offset,last,bp);
  290.         tfp->prev = lastfrag;
  291.         tfp->next = nextfrag;
  292.         if(lastfrag != NULLFRAG)
  293.             lastfrag->next = tfp;    /* Middle of list */
  294.         else
  295.             rp->fraglist = tfp;    /* First on list */
  296.         if(nextfrag != NULLFRAG)
  297.             nextfrag->prev = tfp;
  298.         break;
  299.     case APPEND:    /* Append to lastfrag */
  300.         append(&lastfrag->buf,bp);
  301.         lastfrag->last = last;    /* Extend forward */
  302.         break;
  303.     case PREPEND:    /* Prepend to nextfrag */
  304.         tbp = nextfrag->buf;
  305.         nextfrag->buf = bp;
  306.         append(&nextfrag->buf,tbp);
  307.         nextfrag->offset = ip->offset;    /* Extend backward */
  308.         break;
  309.     case (APPEND|PREPEND):
  310.         /* Consolidate by appending this fragment and nextfrag
  311.          * to lastfrag and removing the nextfrag descriptor
  312.          */
  313.         append(&lastfrag->buf,bp);
  314.         append(&lastfrag->buf,nextfrag->buf);
  315.         nextfrag->buf = NULLBUF;
  316.         lastfrag->last = nextfrag->last;
  317.  
  318.         /* Finally unlink and delete the now unneeded nextfrag */
  319.         lastfrag->next = nextfrag->next;
  320.         if(nextfrag->next != NULLFRAG)
  321.             nextfrag->next->prev = lastfrag;
  322.         freefrag(nextfrag);
  323.         break;
  324.     }
  325.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  326.         && rp->length != 0){
  327.         /* We've gotten a complete datagram, so extract it from the
  328.          * reassembly buffer and pass it on.
  329.          */
  330.         bp = rp->fraglist->buf;
  331.         rp->fraglist->buf = NULLBUF;
  332.         /* Tell IP the entire length */
  333.         ip->length = rp->length + (IPLEN + ip->optlen);
  334.         free_reasm(rp);
  335.         ipReasmOKs++;
  336.         return bp;
  337.     } else
  338.         return NULLBUF;
  339. }
  340. /* Arrange for receipt of raw IP datagrams */
  341. struct raw_ip *
  342. raw_ip(protocol,r_upcall)
  343. int protocol;
  344. void (*r_upcall)();
  345. {
  346.     register struct raw_ip *rp;
  347.  
  348.     rp = (struct raw_ip *)callocw(1,sizeof(struct raw_ip));
  349.     rp->protocol = protocol;
  350.     rp->r_upcall = r_upcall;
  351.     rp->next = Raw_ip;
  352.     if(rp->next != NULLRIP)
  353.         rp->next->prev = rp;
  354.     Raw_ip = rp;
  355.     return rp;
  356. }
  357. /* Free a raw IP descriptor */
  358. void
  359. del_ip(rpp)
  360. struct raw_ip *rpp;
  361. {
  362.     register struct raw_ip *rp;
  363.  
  364.     /* Do sanity check on arg */
  365.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next)
  366.         if(rp == rpp)
  367.             break;
  368.     if(rp == NULLRIP)
  369.         return;    /* Doesn't exist */
  370.  
  371.     /* Unlink */
  372.     if(rp->prev != NULLRIP)
  373.         rp->prev->next = rp->next;
  374.     else
  375.         Raw_ip = rp->next;
  376.     if(rp->next != NULLRIP)
  377.         rp->next->prev = rp->prev;
  378.     /* Free resources */
  379.     free_q(&rp->rcvq);
  380.     free((char *)rp);
  381. }
  382.  
  383. static struct reasm *
  384. lookup_reasm(ip)
  385. struct ip *ip;
  386. {
  387.     register struct reasm *rp;
  388.  
  389.     for(rp = Reasmq;rp != NULLREASM;rp = rp->next){
  390.         if(ip->source == rp->source && ip->dest == rp->dest
  391.          && ip->protocol == rp->protocol && ip->id == rp->id)
  392.             return rp;
  393.     }
  394.     return NULLREASM;
  395. }
  396. #ifdef    FOO
  397. static
  398. int16
  399. hash_reasm(source,dest,protocol,id)
  400. int32 source;
  401. int32 dest,
  402. char protocol;
  403. int16 id;
  404. {
  405.     register unsigned int hval;
  406.  
  407.     hval = loword(source);
  408.     hval ^= hiword(source);
  409.     hval ^= loword(dest);
  410.     hval ^= hiword(dest);
  411.     hval ^= uchar(protocol);
  412.     hval ^= id;
  413.     return hval % RHASH;
  414. }
  415. #endif
  416. /* Create a reassembly descriptor,
  417.  * put at head of reassembly list
  418.  */
  419. static struct reasm *
  420. creat_reasm(ip)
  421. register struct ip *ip;
  422. {
  423.     register struct reasm *rp;
  424.  
  425.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  426.         return rp;    /* No space for descriptor */
  427.     rp->source = ip->source;
  428.     rp->dest = ip->dest;
  429.     rp->id = ip->id;
  430.     rp->protocol = ip->protocol;
  431.     rp->timer.start = (ipReasmTimeout * 1000) / MSPTICK;
  432.     rp->timer.func = ip_timeout;
  433.     rp->timer.arg = rp;
  434.  
  435.     rp->next = Reasmq;
  436.     if(rp->next != NULLREASM)
  437.         rp->next->prev = rp;
  438.     Reasmq = rp;
  439.     return rp;
  440. }
  441.  
  442. /* Free all resources associated with a reassembly descriptor */
  443. static void
  444. free_reasm(rp)
  445. register struct reasm *rp;
  446. {
  447.     register struct frag *fp;
  448.  
  449.     stop_timer(&rp->timer);
  450.     /* Remove from list of reassembly descriptors */
  451.     if(rp->prev != NULLREASM)
  452.         rp->prev->next = rp->next;
  453.     else
  454.         Reasmq = rp->next;
  455.     if(rp->next != NULLREASM)
  456.         rp->next->prev = rp->prev;
  457.     /* Free any fragments on list, starting at beginning */
  458.     while((fp = rp->fraglist) != NULLFRAG){
  459.         rp->fraglist = fp->next;
  460.         free_p(fp->buf);
  461.         free((char *)fp);
  462.     }
  463.     free((char *)rp);
  464. }
  465.  
  466. /* Handle reassembly timeouts by deleting all reassembly resources */
  467. static void
  468. ip_timeout(arg)
  469. void *arg;
  470. {
  471.     register struct reasm *rp;
  472.  
  473.     rp = (struct reasm *)arg;
  474.     free_reasm(rp);
  475.     ipReasmFails++;
  476. }
  477. /* Create a fragment */
  478. static
  479. struct frag *
  480. newfrag(offset,last,bp)
  481. int16 offset,last;
  482. struct mbuf *bp;
  483. {
  484.     struct frag *fp;
  485.  
  486.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  487.         /* Drop fragment */
  488.         free_p(bp);
  489.         return NULLFRAG;
  490.     }
  491.     fp->buf = bp;
  492.     fp->offset = offset;
  493.     fp->last = last;
  494.     return fp;
  495. }
  496. /* Delete a fragment, return next one on queue */
  497. static
  498. void
  499. freefrag(fp)
  500. struct frag *fp;
  501. {
  502.     free_p(fp->buf);
  503.     free((char *)fp);
  504. }
  505.